package buber.genetic;

import java.util.Iterator;

import buber.config.Config;
import buber.genetic.interfaces.Algorithm;
import buber.genetic.interfaces.Member;
import buber.genetic.interfaces.Population;
import buber.genetic.interfaces.Score;
import buber.genetic.op.interfaces.CloneOp;
import buber.genetic.op.interfaces.CrossOp;
import buber.genetic.op.interfaces.MutateOp;
import buber.genetic.op.interfaces.SelectOp;

public class SimpleAlgorithm implements Algorithm{
	private MutateOp mutator;
	private CrossOp crosser;
	private SelectOp selector;
	private CloneOp cloner;
	private Population pop;
	private Score score;
	private int popSize=10;
	private int generations=100;
	private double mutationP=0.1d;
	public SimpleAlgorithm(){
		
	};
	public void config(Config cfg){
		popSize=cfg.getPopSize();
		generations=cfg.getGenerations();
		mutationP=cfg.getMutationRatio();
	}
	public void init(){
		//utworzenie populacji początkowej
		for(int i=0;i<popSize;i++){
			pop.addMember(pop.getRandomMemeber());
		}
		selector.setPopulation(pop);
		selector.sortPopulation();

	};
	public void doAlgorithm() {
		int x=0;
		
		if(checkConditions()){
			mutator.setMutationProb(mutationP);
			Population nowa = pop;
			Double maxPossibleScore=score.getMaxScore(pop.getRandomMemeber());
			Double maxScore=0.0;
			while((x<generations)&&(!score.isOptimal(maxScore,pop.getMembers().get(0)))){
				String gString=String.valueOf(x);;
				if(x<10){
					gString="0"+gString;
					
				}
				System.out.print("[alg] genration:"+gString);
				//System.out.println(populationAsString());
				nowa=pop.getClone();
				//nowa=cloner.doOperator(pop); 
				nowa=mutator.doOperator(nowa);//System.out.println("[rozmiarNowa]="+nowa.size());
				nowa=crosser.doOperator(nowa);
				pop=pop.joinWith(nowa);//System.out.println("[rozmiarStara]="+pop.size());
				pop=selector.doOperator(pop);//System.out.println("[rozmiarStara]="+pop.size());
				x++;
				nowa.genocide();
				maxScore = score.getScore(pop.getMembers().get(0));
				System.out.println(" best:"+getBest().asString()+"="+maxScore);
			}
		}
		else{
			System.out.println("[algorithm] set operators and score first");
		}
	};
	public Population getPopulation() {
		// TODO Auto-generated method stub
		return pop;
	};

	public void setPopulation(Population p) {
		this.pop=p;
		
	};
	public MutateOp getMutator() {
		return mutator;
	};
	public void setMutator(MutateOp mutator) {
		this.mutator = mutator;
	};
	public SelectOp getSelector() {
		return selector;
	};
	public void setSelector(SelectOp selector) {
		this.selector = selector;
	};
	public CloneOp getCloner() {
		return cloner;
	};
	public void setCloner(CloneOp cloner) {
		this.cloner = cloner;
	};
	
	public Score getScore() {
		return score;
	};
	public void setScore(Score score) {
		this.score = score;
		if(this.selector==null){
			System.out.println("[algorithm] selector nie ustawiony!");
		}
		else{
			this.selector.setScore(score);
		}
	};
	public String populationAsString(){
		StringBuffer sb = new StringBuffer();
		for(Iterator<Member> pit = pop.getMembers().iterator();pit.hasNext();){
			Member m =pit.next(); 
			sb.append(m.asString());
			sb.append(" = ");
			sb.append(score.getScore(m));
			sb.append("\n");
		};
		return sb.toString();
	}
	public boolean checkConditions(){
		if((crosser!=null)&&(selector!=null)&&(mutator!=null)&&(cloner!=null)&&(score!=null)){
			return true;
		}
		else{
			return false;
		}
	}
	public CrossOp getCrosser() {
		return crosser;
	}
	public void setCrosser(CrossOp crosser) {
		this.crosser = crosser;
	}
	public Member getBest() {
		selector.sortPopulation();
		return pop.getMembers().get(0);
	}
	
};
